﻿using Common.Logging;
using System;
using System.Collections.Generic;

namespace Xmart.Data
{
    /// <summary>
    /// 数据访问模版
    /// </summary>
    public class ModelTemplate
    {
        #region 构造

        public ModelTemplate(NHibernate.ISessionFactory sessionFactory)
        {
            SessionFactory = sessionFactory;
        }

        #endregion

        #region 字段

        /// <summary>
        /// 通用模版
        /// </summary>
        protected Spring.Data.NHibernate.Generic.HibernateTemplate Template { get; set; }

        ILog log = LogManager.GetCurrentClassLogger();
        #endregion

        #region 属性

        /// <summary>
        /// SessionFactory
        /// </summary>
        public NHibernate.ISessionFactory SessionFactory
        {
            protected get { return Template.SessionFactory; }
            set { Template = new Spring.Data.NHibernate.Generic.HibernateTemplate(value); }
        }

        #endregion

        #region 方法

        /// <summary>
        /// 查询全部
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public IList<T> ExecuteQuery<T>()
        {
            log.DebugFormat("ExecuteQuery:{0}", typeof(T));
            return Template.LoadAll<T>();
        }

        /// <summary>
        /// 按循序条件查询
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="hql"></param>
        /// <param name="args"></param>
        /// <returns></returns>
        public IList<T> ExecuteQuery<T>(string hql, params object[] args)
        {
            log.DebugFormat("ExecuteQuery:{0},hql:{1},args:{2}", typeof(T), hql, args);

            return Template.Find<T>(hql, args);
        }

        /// <summary>
        /// 按命名条件查询
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="hql"></param>
        /// <param name="names"></param>
        /// <param name="values"></param>
        /// <returns></returns>
        public IList<T> ExecuteQuery<T>(string hql, string[] names, object[] values)
        {
            log.DebugFormat("ExecuteQuery:{0},hql:{1},names:{2},values:{3}", typeof(T), hql, names, values);

            return Template.FindByNamedParam<T>(hql, names, values);
        }

        /// <summary>
        /// 列表回调查询
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="func"></param>
        /// <returns></returns>
        public IList<T> ExecuteQuery<T>(Func<NHibernate.ISession, IList<T>> func)
        {
            log.DebugFormat("ExecuteQuery:{0},func:{1}", typeof(T), func);

            return Template.ExecuteFind<T>((s) => { return func(s); });
        }

        /// <summary>
        /// 单项回调查询
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="func"></param>
        /// <returns></returns>
        public T ExecuteQuery<T>(Func<NHibernate.ISession, T> func)
        {
            log.DebugFormat("ExecuteQuery:{0},func:{1}", typeof(T), func);

            return Template.Execute<T>((s) => { return func(s); });
        }

        /// <summary>
        /// 新增
        /// </summary>
        /// <param name="target"></param>
        public void ExecuteSave(object target)
        {
            log.DebugFormat("ExecuteSave:{0},target:{1}", target.GetType(), target);

            Template.Save(target);
        }

        /// <summary>
        /// 更新
        /// </summary>
        /// <param name="target"></param>
        public void ExecuteUpdate(object target)
        {
            log.DebugFormat("ExecuteUpdate:{0},target:{1}", target.GetType(), target);

            Template.Update(target);
        }

        /// <summary>
        /// 新增或更新
        /// </summary>
        /// <param name="target"></param>
        public void ExecuteSaveOrUpdate(object target)
        {
            log.DebugFormat("ExecuteSaveOrUpdate:{0},target:{1}", target.GetType(), target);

            Template.SaveOrUpdate(target);
        }

        /// <summary>
        /// 单项删除
        /// </summary>
        /// <param name="target"></param>
        public void ExecuteDelete(object target)
        {
            log.DebugFormat("ExecuteDelete:{0},target:{1}", target.GetType(), target);

            Template.Delete(target);
        }

        /// <summary>
        /// 条件删除
        /// </summary>
        /// <param name="hql"></param>
        /// <param name="args"></param>
        /// <param name="types"></param>
        public void ExecuteDelete(string hql, object[] args, NHibernate.Type.IType[] types)
        {
            log.DebugFormat("ExecuteDelete:{0},hql:{1}", hql);

            Template.Delete(hql, args, types);
        }

        /// <summary>
        /// 通用回调
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="func"></param>
        /// <returns></returns>
        public T ExecuteCallback<T>(Func<NHibernate.ISession, T> func)
        {
            log.DebugFormat("ExecuteCallback:{0},func:{1}", typeof(T), func);

            return Template.Execute((s) => { return func(s); });
        }

        /// <summary>
        /// 事务回调
        /// </summary>
        /// <param name="action"></param>
        public void ExecuteTransaction(Action<NHibernate.ISession> action)
        {
            using (var session = Template.SessionFactory.OpenSession())
            {
                log.Debug("BeginTransaction");
                using (var trans = session.BeginTransaction())
                {
                    try
                    {
                        action(session);
                        trans.Commit();
                        log.Debug("CommitTransaction");
                    }
                    catch (Exception ex)
                    {
                        trans.Rollback();
                        log.Error("RollbackTransaction", ex);
                        throw;
                    }
                }
            }
        }

        #endregion

    }
}
